Use GDK's current window tracking when synthesizing events in GTK+
authorOwen W. Taylor <otaylor@fishsoup.net>
Wed, 12 Mar 2014 16:39:03 +0000 (12:39 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Thu, 13 Mar 2014 03:03:53 +0000 (23:03 -0400)
Add gdk_device_get_last_event_window(), and use to implement the window
tracking we need for synthesizing crossing events for sensitivity changes
and gtk grabs, rather than keeping the information in qdata and updating
it based when GTK+ gets events.

https://bugzilla.gnome.org/show_bug.cgi?id=726187

docs/reference/gdk/gdk3-sections.txt
gdk/gdkdevice.c
gdk/gdkdevice.h
gtk/gtkmain.c
gtk/gtkwidget.c

index d23183a3dd62ad24e4c5b55d7843d9783a56bd5b..51963aa48c92a2102cf77b4ececae1d7ee12f054 100644 (file)
@@ -736,6 +736,7 @@ GdkTimeCoord
 gdk_device_get_axis
 gdk_device_list_axes
 gdk_device_get_axis_value
+gdk_device_get_last_event_window
 
 <SUBSECTION Standard>
 GDK_TYPE_AXIS_USE
index 9508a7be13f4cd579b9e819a74a72e7b3f2e0c24..24499d79652c45a91524443c7647354925b8a06e 100644 (file)
@@ -1717,3 +1717,30 @@ _gdk_device_window_at_position (GdkDevice        *device,
                                                             mask,
                                                             get_toplevel);
 }
+
+/**
+ * gdk_device_get_last_event_window:
+ * @device: a #GdkDevice, with a source other than %GDK_SOURCE_KEYBOARD
+ *
+ * Gets information about which window the given pointer device is in, based on
+ * that have been received so far from the display server. If another application
+ * has a pointer grab, or this application has a grab with owner_events = %FALSE,
+ * %NULL may be returned even if the pointer is physically over one of this
+ * application's windows.
+ *
+ * Returns: (transfer none) (allow-none): the last window the device
+ */
+GdkWindow *
+gdk_device_get_last_event_window (GdkDevice *device)
+{
+  GdkDisplay *display;
+  GdkPointerWindowInfo *info;
+
+  g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
+  g_return_val_if_fail (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD, NULL);
+
+  display = gdk_device_get_display (device);
+  info = _gdk_display_get_pointer_info (display, device);
+
+  return info->window_under_pointer;
+}
index a67f4b589052c5bc41ee828f82ad3ba3b5c6b173..23b3551d099649c9ea9e93d794021f24bbedc030 100644 (file)
@@ -271,6 +271,8 @@ gboolean gdk_device_grab_info_libgtk_only (GdkDisplay  *display,
                                            GdkWindow  **grab_window,
                                            gboolean    *owner_events);
 
+GDK_AVAILABLE_IN_3_12
+GdkWindow *gdk_device_get_last_event_window (GdkDevice *device);
 
 G_END_DECLS
 
index c3367e1af4181eb703802ac2c442325fcb37c700..9e8fea58172c69ae5a7a973c7759a03fbe21d6ca 100644 (file)
@@ -1736,22 +1736,12 @@ gtk_main_do_event (GdkEvent *event)
       break;
 
     case GDK_ENTER_NOTIFY:
-      if (event->crossing.detail != GDK_NOTIFY_VIRTUAL &&
-          event->crossing.detail != GDK_NOTIFY_NONLINEAR_VIRTUAL)
-        _gtk_widget_set_device_window (event_widget,
-                                       gdk_event_get_device (event),
-                                       event->any.window);
       if (gtk_widget_is_sensitive (grab_widget) &&
           !_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
         gtk_widget_event (grab_widget, event);
       break;
 
     case GDK_LEAVE_NOTIFY:
-      if (event->crossing.detail != GDK_NOTIFY_VIRTUAL &&
-          event->crossing.detail != GDK_NOTIFY_NONLINEAR_VIRTUAL)
-        _gtk_widget_set_device_window (event_widget,
-                                       gdk_event_get_device (event),
-                                       NULL);
       if (gtk_widget_is_sensitive (grab_widget) &&
           !_gtk_propagate_captured_event (grab_widget, event, topmost_widget))
         gtk_widget_event (grab_widget, event);
index 5c691a1cbf10aa55ff0be04e7b0e013882f3effd..5488c66abdbcf1858404ef7682d30e00b65772a7 100644 (file)
@@ -855,7 +855,6 @@ static GQuark               quark_accel_closures = 0;
 static GQuark          quark_event_mask = 0;
 static GQuark           quark_device_event_mask = 0;
 static GQuark          quark_parent_window = 0;
-static GQuark          quark_pointer_window = 0;
 static GQuark          quark_shape_info = 0;
 static GQuark          quark_input_shape_info = 0;
 static GQuark          quark_pango_context = 0;
@@ -1022,7 +1021,6 @@ gtk_widget_class_init (GtkWidgetClass *klass)
   quark_event_mask = g_quark_from_static_string ("gtk-event-mask");
   quark_device_event_mask = g_quark_from_static_string ("gtk-device-event-mask");
   quark_parent_window = g_quark_from_static_string ("gtk-parent-window");
-  quark_pointer_window = g_quark_from_static_string ("gtk-pointer-window");
   quark_shape_info = g_quark_from_static_string ("gtk-shape-info");
   quark_input_shape_info = g_quark_from_static_string ("gtk-input-shape-info");
   quark_pango_context = g_quark_from_static_string ("gtk-pango-context");
@@ -4627,9 +4625,6 @@ gtk_widget_unmap (GtkWidget *widget)
       g_signal_emit (widget, widget_signals[UNMAP], 0);
 
       gtk_widget_pop_verify_invariants (widget);
-
-      /* Unset pointer/window info */
-      g_object_set_qdata (G_OBJECT (widget), quark_pointer_window, NULL);
     }
 }
 
@@ -11780,49 +11775,14 @@ _gtk_widget_peek_request_cache (GtkWidget *widget)
   return &widget->priv->requests;
 }
 
-/*
- * _gtk_widget_set_device_window:
- * @widget: a #GtkWidget
- * @device: a #GdkDevice
- * @window: the new device window
- *
- * Sets pointer window for @widget and @device.
- * Does not ref @window.
- */
-void
-_gtk_widget_set_device_window (GtkWidget *widget,
-                               GdkDevice *device,
-                               GdkWindow *window)
+static gboolean
+is_my_window (GtkWidget *widget,
+              GdkWindow *window)
 {
-  GHashTable *device_window;
-
-  g_return_if_fail (GTK_IS_WIDGET (widget));
-  g_return_if_fail (GDK_IS_DEVICE (device));
-  g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
-
-  if (!gtk_widget_get_mapped (widget))
-    return;
-
-  device_window = g_object_get_qdata (G_OBJECT (widget), quark_pointer_window);
-
-  if (!device_window && window)
-    {
-      device_window = g_hash_table_new (NULL, NULL);
-      g_object_set_qdata_full (G_OBJECT (widget),
-                               quark_pointer_window,
-                               device_window,
-                               (GDestroyNotify) g_hash_table_destroy);
-    }
-
-  if (window)
-    g_hash_table_insert (device_window, device, window);
-  else if (device_window)
-    {
-      g_hash_table_remove (device_window, device);
+  gpointer user_data;
 
-      if (g_hash_table_size (device_window) == 0)
-        g_object_set_qdata (G_OBJECT (widget), quark_pointer_window, NULL);
-    }
+  gdk_window_get_user_data (window, &user_data);
+  return (user_data == widget);
 }
 
 /*
@@ -11830,26 +11790,44 @@ _gtk_widget_set_device_window (GtkWidget *widget,
  * @widget: a #GtkWidget
  * @device: a #GdkDevice
  *
- * Returns: the device window set on @widget, or %NULL
+ * Returns: the window of @widget that @device is in, or %NULL
  */
 GdkWindow *
 _gtk_widget_get_device_window (GtkWidget *widget,
                                GdkDevice *device)
 {
-  GHashTable *device_window;
+  GdkWindow *window;
 
   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
   g_return_val_if_fail (GDK_IS_DEVICE (device), NULL);
 
-  if (!gtk_widget_get_mapped (widget))
+  window = gdk_device_get_last_event_window (device);
+  if (window && is_my_window (widget, window))
+    return window;
+  else
     return NULL;
+}
 
-  device_window = g_object_get_qdata (G_OBJECT (widget), quark_pointer_window);
-
-  if (!device_window)
-    return NULL;
+static void
+list_devices (GtkWidget        *widget,
+              GdkDeviceManager *device_manager,
+              GdkDeviceType     device_type,
+              GList           **result)
+{
+  GList *devices = gdk_device_manager_list_devices (device_manager, device_type);
+  GList *l;
 
-  return g_hash_table_lookup (device_window, device);
+  for (l = devices; l; l = l->next)
+    {
+      GdkDevice *device = l->data;
+      if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
+        {
+          GdkWindow *window = gdk_device_get_last_event_window (device);
+          if (window && is_my_window (widget, window))
+            *result = g_list_prepend (*result, device);
+        }
+    }
+  g_list_free (devices);
 }
 
 /*
@@ -11864,27 +11842,22 @@ _gtk_widget_get_device_window (GtkWidget *widget,
 GList *
 _gtk_widget_list_devices (GtkWidget *widget)
 {
-  GHashTableIter iter;
-  GHashTable *device_window;
-  GList *devices = NULL;
-  gpointer key, value;
+  GdkDisplay *display;
+  GdkDeviceManager *device_manager;
+  GList *result = NULL;
 
   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
 
+  display = gtk_widget_get_display (widget);
+  device_manager = gdk_display_get_device_manager (display);
   if (!gtk_widget_get_mapped (widget))
     return NULL;
 
-  device_window = g_object_get_qdata (G_OBJECT (widget), quark_pointer_window);
+  list_devices (widget, device_manager, GDK_DEVICE_TYPE_MASTER, &result);
+  /* Rare, but we can get events for grabbed slave devices */
+  list_devices (widget, device_manager, GDK_DEVICE_TYPE_SLAVE, &result);
 
-  if (G_UNLIKELY (!device_window))
-    return NULL;
-
-  g_hash_table_iter_init (&iter, device_window);
-
-  while (g_hash_table_iter_next (&iter, &key, &value))
-    devices = g_list_prepend (devices, key);
-
-  return devices;
+  return result;
 }
 
 static void